package com.zzyl.serve.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.serve.domain.AlertData;
import com.zzyl.serve.domain.DeviceData;
import com.zzyl.serve.mapper.DeviceMapper;
import com.zzyl.system.mapper.SysUserRoleMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.serve.mapper.AlertRuleMapper;
import com.zzyl.serve.domain.AlertRule;
import com.zzyl.serve.service.IAlertRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 报警规则Service业务层处理
 * 
 * @author Huanghc
 * @date 2025-08-26
 */
@Service
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService
{
    @Autowired
    private AlertRuleMapper alertRuleMapper;
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private SysUserRoleMapper userRoleMapper;
    @Autowired
    private AlertDataServiceImpl alertDataService;


    @Override
    public void alertFilter() {


        //先查数据库是否是有报警规矩是启动状态；如果没有直接返回
        LambdaQueryWrapper<AlertRule> wrapper = Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getStatus, 1);
        long count = count(wrapper);
        if(count<0){
            return;
        }
        //再从redits中拿到最新的数据，如果没有直接返回
        List<Object> deviceDataList = redisTemplate.opsForHash().values(CacheConstants.IOT_DEVICE_LAST_DATA);
        if(ObjectUtil.isEmpty(deviceDataList)){
            return;
        }
        //循环数据将转化成对象格式
        for(Object deviceData:deviceDataList){
            List<DeviceData> list = JSONUtil.toList(deviceData.toString(), DeviceData.class);
            //循环处理数据，判断每一条数据是否触发了警报，用方法去判断
            for (DeviceData data : list) {
                alertFilters(data);
            }
        }
        }

    private void alertFilters(DeviceData deviceData) {

        //如果数据超过了一分钟不处理，不加1
        long between = LocalDateTimeUtil.between(deviceData.getAlarmTime(), LocalDateTime.now(), ChronoUnit.SECONDS);
        if(between>60){
            return;
        }
        //查找针对此设备有效的所有规则,如果没有直接返回
        List<AlertRule> alertRules = list(Wrappers.<AlertRule>lambdaQuery()
                .eq(AlertRule::getProductKey,deviceData.getProductKey())
                .eq(AlertRule::getFunctionId,deviceData.getFunctionId())
                .in(AlertRule::getIotId,-1,deviceData.getIotId())
                .eq(AlertRule::getStatus,1));
        if(ObjectUtil.isEmpty(alertRules)){
            return;
        }
        //遍历每个规则，分别对这些数据进行判定
        alertRules.forEach(alertRule -> deviceDataAlarmHandle(alertRule,deviceData));

        //如果数据正常清除次数

        //报警
        //如果是位置设备，找维修人员，
        //如果是随身设备，找老人的护理人员，
        //再将超级管理添加进去
    }

    private void deviceDataAlarmHandle(AlertRule alertRule, DeviceData deviceData) {

        //如果不在规则的生效时间内，不处理
        String[] period  = alertRule.getAlertEffectivePeriod().split("~");
        LocalTime start  = LocalTime.parse(period[0]);
        LocalTime end    = LocalTime.parse(period[1]);
        LocalTime alarmTime = deviceData.getAlarmTime().toLocalTime();
        if(alarmTime.isBefore(start)||alarmTime.isAfter(end)){
            return;
        }
        String alertCountCacheKey = StringUtils.format(CacheConstants.ALERT_COUNT_KEY,deviceData.getIotId(),alertRule.getId());
        if(">=".equals(alertRule.getOperator())&&Double.valueOf(deviceData.getDataValue())>=alertRule.getValue()
                ||"<".equals(alertRule.getOperator())&&Double.valueOf(deviceData.getDataValue())<alertRule.getValue()){
            log.error("设备数据符合报警阈值条件");
        }else {
            redisTemplate.delete(alertCountCacheKey);
            return;
        }
        //如果在沉默期，不处理
        String alertSilentFlagKey = StringUtils.format(CacheConstants.ALERT_RULE_SILENT_KEY,deviceData.getIotId(),alertRule.getId());
        Object silentNow  =redisTemplate.opsForValue().get(alertSilentFlagKey);
        if(ObjectUtil.isNotEmpty(silentNow)){
            return;
        }
        Long count = redisTemplate.opsForValue().increment(alertCountCacheKey,1);
        if(count==null||count<alertRule.getDuration()){
            return;
        }
        //成功触发警报
        redisTemplate.delete(alertCountCacheKey);
        redisTemplate.opsForValue().set(alertSilentFlagKey,"1",alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);
        //找到报警的责任人
        Set<Long> userIds = new HashSet<>();
        //如果是设备异常，找维修人员
        if(alertRule.getAlertDataType()==0){
            if(ObjectUtil.equals(deviceData.getLocationType(),0)){
                //随身设备，根据设备Id直接找到老人护理员
                userIds = deviceMapper.selectNurseIdsByElderIotId(deviceData.getIotId());

            }else if(ObjectUtil.equals(deviceData.getLocationType(),1)){
                //根据床位Id找到老人id，再找到老人护理员
                userIds = deviceMapper.selectNurseIdsByBedIotId(deviceData.getIotId());
            }else if(alertRule.getAlertDataType()==1){
                //设备异常，根据名称找到维修人员
                userIds =  userRoleMapper.selectUserIdsByRoleName("维修工");
            }
        }
        //将超级管理员也添加到责任人中
        Set<Long> admins = userRoleMapper.selectUserIdsByRoleName("超级管理员");
        userIds.addAll(admins);
        //封装数据
        batchSaveAlertData(userIds,alertRule,deviceData);

    }

    private void batchSaveAlertData(Set<Long> userIds, AlertRule alertRule, DeviceData deviceData) {

        List<AlertData> alertDataList = new ArrayList<>();
        String reason = alertRule.getFunctionName()+alertRule.getOperator()+alertRule.getValue()+",持续"+alertRule.getDuration()+",个周期，发出警报";
        for (Long userId : userIds) {
            AlertData alertData = new AlertData();
            BeanUtils.copyProperties(deviceData,alertData);
            alertData.setId(null);
            alertData.setAlertRuleId(alertRule.getId());
            alertData.setAlertReason(reason);
            alertData.setType(alertRule.getAlertDataType());
            alertData.setStatus(0);
            alertData.setUserId(userId);
            alertDataList.add(alertData);

        }
            alertDataService.saveBatch(alertDataList);
    }


    /**
     * 查询报警规则
     * 
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id)
    {
        return alertRuleMapper.selectById(id);
    }

    /**
     * 查询报警规则列表
     * 
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule)
    {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     * 
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule)
    {
        return alertRuleMapper.insert(alertRule);
    }

    /**
     * 修改报警规则
     * 
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule)
    {
        return alertRuleMapper.updateById(alertRule);
    }

    /**
     * 批量删除报警规则
     * 
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids)
    {
        return alertRuleMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除报警规则信息
     * 
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id)
    {
        return alertRuleMapper.deleteById(id);
    }


}
